import Singleton from "../Base/Singleton";
import { ApiMsgEnum, binaryDecode, binaryEncode, IModel } from "../Common";

interface IItem {
	cb: Function;
	ctx: unknown;
}

interface ICallApiRes<T> {
	success: boolean;
	res?: T;
	error?: Error;
}

export class NetworkManager extends Singleton {
	static get Instance() {
		return super.GetInstance<NetworkManager>();
	}

	isConnected: boolean = false;
	port: number = 9876;
	ws: WebSocket = null;

	private map: Map<ApiMsgEnum, Array<IItem>> = new Map();
	connect() {
		return new Promise((resolve, reject) => {
			if (this.isConnected) {
				resolve(true)
				return;
			}
			this.ws = new WebSocket(`ws://localhost:${this.port}`);
			this.ws.binaryType = "arraybuffer"
			this.ws.onopen = () => {
				resolve(true)
				console.log("网络连接成功！")
				this.isConnected = true;
			}
			this.ws.onclose = () => {
				reject(false)
				this.isConnected = false;
			}
			this.ws.onmessage = (e) => {
				try {
					// console.log("onmessage ", e.data);
					//客户端接收ArrayBuffer数据

					//初始字符编码数据
					// const typeArray = new Uint8Array(e.data)
					// const str = strdecode(typeArray)
					// const json = JSON.parse(str);

					//二进制压缩编码数据
					const json = binaryDecode(e.data);
					const { name, data } = json;

					if (this.map.has(name)) {
						this.map.get(name).forEach(({ cb, ctx }) => {
							cb.call(ctx, data);
						});
					}
				} catch (error) {
					console.log(error)
				}
			}
			this.ws.onerror = (err) => {
				console.log(err);
				reject(false)
				this.isConnected = false;
			}
		})
	}

	callApi<T extends keyof IModel['api']>(name: T, data: IModel['api'][T]['req']): Promise<ICallApiRes<IModel['api'][T]['res']>> {
		return new Promise((resolve, reject) => {
			try {
				const timer = setTimeout(() => {
					resolve({ success: false, error: new Error("Time Out!") })
					this.unlistenMsg(name as any, cb, null)
				}, 5000)
				const cb = (res) => {
					resolve(res)
					clearTimeout(timer)
					this.unlistenMsg(name as any, cb, null)
				}
				this.listenMsg(name as any, cb, null)
				this.sendMsg(name as any, data)
			} catch (error) {
				resolve({ success: false, error })
			}
		})
	}

	sendMsg<T extends keyof IModel['msg']>(name: T, data: IModel['msg'][T]) {

		//初始字符编码数据
		// let msg = {
		// 	name,
		// 	data
		// }
		// const str = JSON.stringify(msg)
		// const typeArray = strencode(str);

		// const buffer = new ArrayBuffer(typeArray.length);
		// const dataView = new DataView(buffer)
		// for (let i = 0; i < typeArray.length; i++) {
		// 	dataView.setUint8(i, typeArray[i]);
		// }

		//二进制压缩编码数据
		const dataView = binaryEncode(name, data)
		//客户端发送ArrayBuffer数据
		this.ws.send(dataView.buffer)
	}

	listenMsg<T extends keyof IModel['msg']>(name: T, cb: (args: IModel['msg'][T]) => void, ctx: unknown) {
		if (this.map.has(name)) {
			this.map.get(name).push({ cb, ctx });
		} else {
			this.map.set(name, [{ cb, ctx }]);
		}
	}

	unlistenMsg<T extends keyof IModel['msg']>(name: T, cb: (args: IModel['msg'][T]) => void, ctx: unknown) {
		if (this.map.has(name)) {
			const index = this.map.get(name).findIndex((i) => cb === i.cb && i.ctx === ctx);
			index > -1 && this.map.get(name).splice(index, 1);
		}
	}
}
